package com.crowntit.config;

import com.crowntit.types.annotations.DCCValue;
import com.crowntit.types.common.Constants;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RBucket;
import org.redisson.api.RTopic;
import org.redisson.api.RedissonClient;
import org.springframework.aop.framework.AopProxyUtils;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

@Configuration
@Slf4j
public class DCCValueBeanFactory implements BeanPostProcessor {

    private static final String BASE_CONFIG_PATH = "group_buy_market_dcc_";
    private final RedissonClient redissonClient;
    private final Map<String, Object> dccObjGroup = new HashMap<>();

    public DCCValueBeanFactory(RedissonClient redissonClient) {
        this.redissonClient = redissonClient;
    }

    @Bean("dccTopic")
    public RTopic addRedisTopicListener(){
        RTopic topic = redissonClient.getTopic("group_buy_market_dcc");
        topic.addListener(String.class, ((charSequence, s) -> {
            log.info("监听器触发");

            String[] split = s.split(Constants.SPLIT);
            String attribute = split[0];
            String key = BASE_CONFIG_PATH + split[0];
            String value = split[1];
            log.info("解析到发布的内容 key:{} value:{}", key, value);

            RBucket rBucket = redissonClient.getBucket(key);
            if (!rBucket.isExists()){
                log.info("redis不存在要配置的字段");
                return;
            }
            rBucket.set(value);

            Object objBean = dccObjGroup.get(key);
            if (objBean == null){
                log.info("程序内不存在要配置的字段");
                return;
            }

            log.info("程序获取目标字段");
            Class<?> objBeanClass = objBean.getClass();
            if (AopUtils.isAopProxy(objBean)){
                objBeanClass = AopUtils.getTargetClass(objBean);
            }

            log.info("获取成功");
            try {
                Field declaredField = objBeanClass.getDeclaredField(attribute);
                declaredField.setAccessible(true);
                declaredField.set(objBean, value);
                log.info("设置成功：目标field为: {}, 值为: {}", declaredField.getName(), declaredField.get(objBean));
                declaredField.setAccessible(false);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }));
        return topic;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        // 注意；增加 AOP 代理后，获得类的方式要通过 AopProxyUtils.getTargetClass(bean); 不能直接 bean.class 因为代理后类的结构发生变化，这样不能获得到自己的自定义注解了。
//        log.info("配置对象初始化");
        Class<?> targetBeanClass = bean.getClass();
        Object targetBeanObject = bean;

        if (AopUtils.isAopProxy(bean)){
            targetBeanClass = AopUtils.getTargetClass(bean);
            targetBeanObject = AopProxyUtils.getSingletonTarget(bean);
        }

        Field[] fields = targetBeanClass.getDeclaredFields();
        for (Field field : fields) {
            if (!field.isAnnotationPresent(DCCValue.class)){
                continue;
            }

            log.info("检测到配置参数");
            DCCValue dccValue = field.getAnnotation(DCCValue.class);
            String value = dccValue.value();
            if (StringUtils.isBlank(value)){
                log.info("初始化参数为空");
                throw new RuntimeException(field.getName() + " @DCCValue is not config value ");
            }

            log.info("解析初始化参数");
            String[] split = value.split(":");
            String key = BASE_CONFIG_PATH + split[0];
            String defaultValue = split.length == 2 ? split[1] : null;
            String setValue = defaultValue;
            log.info("初始化参数解析成功 key: {}, value: {}", key, setValue);

            try {
                if (StringUtils.isBlank(defaultValue)){
                    throw new RuntimeException(field.getName() + " @DCCValue default config is null ");
                }

                RBucket<String> rBucket = redissonClient.getBucket(key);
                if (!rBucket.isExists()){
                    log.info("redis不存在要配置的字段-设置");
                    rBucket.set(defaultValue);
                } else {
                    setValue = rBucket.get();
                    log.info("redis已存在要配置的字段，获取setValue: {}", setValue);
                }

                field.setAccessible(true);
                field.set(targetBeanObject, setValue);
                log.info("设置成功：目标field为: {}, 值为: {}", field.getName(), field.get(targetBeanObject));
                field.setAccessible(false);
            } catch (IllegalAccessException e) {
                throw new RuntimeException(e);
            }
            dccObjGroup.put(key, targetBeanObject);
        }
        return bean;
    }
}
